
#include "DBAccess.h"

/************************************************************************

    FUNCTION:   getMailMessages

 ************************************************************************/

int getMailMessages (char* serverName, char* dbName, char* password, MailMsg *mm){
	char        szMailFilePath[MAXPATH+1];
	STATUS      error = NOERROR;           /* return status Body API calls */

	#ifdef OS390
		/* Need to convert args Body EBCDIC (Native z/OS) to ASCII (how this sample is compiled) */
		__argvtoascii_a(argc,argv);
	#endif

    /*
	 *	Please config the system variables.
	 *	Add Lotus Notes/Domino executable directory to the PATH.
	 */
	if (error = NotesInitExtended (0, NULL))
	{
        printf("\n Unable to initialize Notes.\n");
        return (1);
	}
	OSPathNetConstruct( NULL,               /* port name  */
                    serverName,
                    dbName,
                    szMailFilePath);

	if(NOERROR != handleMailDB(szMailFilePath, serverName,password, mm)){
		NotesTerm();
		return(1);
	}

	/* End of getMailMessages routine. */
    printf("\nProgram completed successfully.\n");
    NotesTerm();
    return NOERROR; 
}

/************************************************************************

    FUNCTION:   handleMailDB

 ************************************************************************/

int handleMailDB(char *szMailFilePath, char* serverName,char *password, MailMsg *mm){
	DBHANDLE    db_handle;      /* handle of source database */
	STATUS      error = NOERROR;           /* return status Body API calls */	

	/* Open the database. */
    
    if (error = NSFDbOpen (szMailFilePath, &db_handle))
    {
        PrintAPIError (error);  
        return (1);
    } 
	if(NOERROR != handleSecurity(serverName,password, db_handle, mm)){
		NSFDbClose (db_handle);
		return(1);
	}

	/* Close the database. */

    if (error = NSFDbClose (db_handle))
    {
        PrintAPIError (error);  
        return (1);
    }
	return NOERROR;
}

/************************************************************************

    FUNCTION:   handleSecurity

 ************************************************************************/

int handleSecurity(char* serverName,char* password, DBHANDLE db_handle, MailMsg *mm){
	STATUS      error = NOERROR;           /* return status Body API calls */
	char        *pPutIDFile = "temp.id";
	KFHANDLE	phKFC;
	DWORD       retFlags;

	if(error = SECExtractIdFileFromDB(db_handle,
							"$shimmerid",
							(DWORD) strlen("$shimmerid"),
							NULL,
							0,
							password,
							pPutIDFile,
							0,
							NULL
							)){
		PrintAPIError (error);  
        return (1);
	}
	if(error = SECRefreshIdFile(pPutIDFile,password,serverName,&retFlags,0,NULL)){
		PrintAPIError (error);  
		remove(pPutIDFile);
        return (1);
	}

	if(retFlags==SEC_refreshed_NotesCerts || retFlags==SEC_refreshed_InternetCerts || retFlags==SEC_refreshed_UserName){
		printf("\nThe ID File is expired.\n");
		remove(pPutIDFile);
		return (1);
	}

	if(error=SECKFMOpen(&phKFC,pPutIDFile,password,SECKFM_open_All,0,NULL)){
		PrintAPIError (error);
		remove(pPutIDFile);
        return (1);
	}

	if(NOERROR !=searchMailMessages(db_handle,&phKFC,mm)){
		SECKFMClose(&phKFC, SECKFM_open_All,0,NULL);
		remove(pPutIDFile);
        return (1);
	}

	if(error=SECKFMClose(&phKFC, SECKFM_open_All,0,NULL)){
		PrintAPIError (error);
		remove(pPutIDFile);
        return (1);
	}

	remove(pPutIDFile);
	return NOERROR;
}

/************************************************************************

    FUNCTION:   searchMailMessages

 ************************************************************************/
int searchMailMessages(DBHANDLE db_handle,KFHANDLE	*phKFC,MailMsg *mm){
	char			 formula[] = "@All"; /* an ASCII selection formula. */
    FORMULAHANDLE    formula_handle;    /* a compiled selection formula */
    WORD			 wdc;                       /* a word we don't care about */
    STATUS			 error = NOERROR;           /* return status Body API calls */
	Para             *pPara;
	Para             para;

	para.db_handle=&db_handle;
	para.phKFC=phKFC;
	para.mm=mm;

	pPara=&para;
	
	/* Compile the selection formula. */

    if (error = NSFFormulaCompile (
                NULL,               /* name of formula (none) */
                (WORD) 0,           /* length of name */
                formula,            /* the ASCII formula */
                (WORD) strlen(formula),    /* length of ASCII formula */
                &formula_handle,    /* handle to compiled formula */
                &wdc,               /* compiled formula length (don't care) */
                &wdc,               /* return code Body compile (don't care) */
                &wdc, &wdc, &wdc, &wdc)) /* compile error info (don't care) */
        
    {
        PrintAPIError (error);
        return (1);
    }

	/* Call NSFSearch to find the notes that match the selection criteria. For 
		each note found, the routine print_fields is called. (If you always want
		to find all the documents in the database, you can set the 2nd argument
		to NULLHANDLE and eliminate the formula compilation.) */

    if (error = NSFSearch (
                db_handle,      /* database handle */
                formula_handle, /* selection formula */
                NULL,           /* title of view in selection formula */
                0,              /* search flags */
                NOTE_CLASS_DOCUMENT,/* note class to find */
                NULL,           /* starting date (unused) */
                parseMailMessage,   /* call for each note found */
                pPara,     /* argument to print_fields */
                NULL))          /* returned ending date (unused) */
    {
        PrintAPIError (error);
        return (1);
    }

	return NOERROR;
}

/************************************************************************

    FUNCTION:   parseMailMessage

 ************************************************************************/

STATUS LNPUBLIC parseMailMessage(void far *argv,SEARCH_MATCH far *pSearchMatch,ITEM_TABLE far *summary_info){
	SEARCH_MATCH SearchMatch;
    NOTEHANDLE   note_handle;
    STATUS       error;
	DBHANDLE     db_handle;
	KFHANDLE	 phKFC;	
	MailMsg		 *mm;
	MailMsg		 *pmm;
	NOTEID       noteID;

	long         *field_id;
	char         *field_from;
	char         *field_to;
	char         *field_bcc;
	char         *field_cc;
	char         *field_subject;
	char         *field_body;
	char         *field_attachments;
	char         *field_postedDate;
	char         empty_test[]="";

	FLAG       fSealed;         /* Is not encrypted? */

	mm=(MailMsg *)malloc(LEN);
	
	db_handle=*(((Para *)argv)->db_handle);
	phKFC=*(((Para *)argv)->phKFC);
	pmm=((Para *)argv)->mm;

	field_id = (long *)malloc(sizeof(long));
	field_from ="";
	field_to="";
	field_bcc="";
	field_cc="";
	field_subject="";
	field_body="";
	field_postedDate="";
	field_attachments=(char *)malloc(sizeof(char[1000]));

	memcpy( (char*)&SearchMatch, (char*)pSearchMatch, sizeof(SEARCH_MATCH) );


	/* Skip this note if it does not really match the search criteria (it is
		now deleted or modified).  This is not necessary for full searches,
		but is shown here in case a starting date was used in the search. */

    if (!(SearchMatch.SERetFlags & SE_FMATCH))
        return (NOERROR);

	/* Open the note. */
	noteID = SearchMatch.ID.NoteID;

    if (error = NSFNoteOpen (
                db_handle,  /* database handle */
                noteID, /* note ID */
                0,                      /* open flags */
                &note_handle))          /* note handle (return) */
        
    return (ERR(error));


	if (NSFNoteIsSignedOrSealed (note_handle, (BOOL far *) NULL, (BOOL far *) &fSealed) ){
		if (fSealed){
			if(error = NSFNoteDecryptExt2(
				note_handle,
				phKFC,
				DECRYPT_ATTACHMENTS_IN_PLACE,
				NULL,
				0,
				NULL)){

			return (ERR(error));
			}
		} 
	}
	
	*field_id = (long)noteID;
	mm->id = field_id;
	getFieldContent(note_handle,"From", &field_from);
	mm->from = field_from;
	getFieldContent(note_handle,"SendTo", &field_to);
	mm->to = field_to;
	getFieldContent(note_handle,"CopyTo", &field_cc);
	mm->copyTo = field_cc;
	getFieldContent(note_handle,"BlindCopyTo", &field_bcc);
	mm->blindCopyTo = field_bcc;
	getFieldContent(note_handle,"Subject", &field_subject);
	mm->subject = field_subject;
	getFieldContent(note_handle,"Body", &field_body);
	mm->body = field_body;
	getFieldContent(note_handle,"PostedDate", &field_postedDate);
	mm->postedDate = field_postedDate;
	mm->next = NULL;

    strcpy_s(field_attachments,1000,empty_test);	
    extractAttachments(note_handle,noteID,field_attachments);
    mm->attachments = field_attachments;

	while(pmm->next!=NULL){
		pmm=pmm->next;
	}
	pmm->next=mm;

	/* Close the note. */

    if (error = NSFNoteClose (note_handle))
        return (ERR(error));

	/* End of subroutine. */

    return (NOERROR);

	
}

/************************************************************************

    FUNCTION:   parseMailMessage

 ************************************************************************/

void getFieldContent(NOTEHANDLE  note_handle,char *item_name,char **item_content){
	BOOL         field_found;
	char         field_text[60 * 1024];
	WORD         field_len = 0;
	char         empty_test[]="";

	field_found = NSFItemIsPresent ( 
                note_handle,
                item_name,
                (WORD) strlen (item_name));

	/* If the field is there, get the contents of the field and 
		print it. */

     if (field_found)
    {
        field_len = NSFItemConvertToText (
                    note_handle,
                    item_name,
                    field_text,
                    (WORD) sizeof (field_text),0);
	 }
	 
    if(field_len!=0) {
         *item_content= (char *)malloc(field_len*sizeof(char)+1);
         strcpy_s(*item_content,field_len*sizeof(char)+1,field_text);
    } else {
        *item_content= (char *)malloc(sizeof(char));
	    strcpy_s(*item_content,1, empty_test);
    }
}

/************************************************************************

    FUNCTION:   extract attachments

 ************************************************************************/

void extractAttachments(NOTEHANDLE  note_handle,NOTEID noteID,char* attachments){
	BOOL         field_found;
	STATUS       error;
	BLOCKID      item_blockid;
	BLOCKID      prev_item_blockid;
	BLOCKID		 value_blockid;

	field_found = NSFItemIsPresent ( 
                note_handle,
                "$FILE",
                (WORD) strlen ("$FILE"));

	if(field_found){
		
		if(error=NSFItemInfo(note_handle,"$FILE",
							(WORD) strlen ("$FILE"),
							&item_blockid,
							NULL,
							&value_blockid,
							NULL)){
			PrintAPIError (error);
			return;
		}

		while (TRUE) {
			extractSingleAttachment(note_handle,noteID,item_blockid,value_blockid,attachments);
			prev_item_blockid = item_blockid; 

			error = NSFItemInfoNext(note_handle, 
								  prev_item_blockid, 
								  "$FILE",  /* name of item we want
												   next; obtain items in
												   in order in note */
								  strlen("$FILE"),  /* name length */
								  &item_blockid,
								  NULL,
								  &value_blockid,
								  NULL);

			if (ERR(error) == ERR_ITEM_NOT_FOUND) {
				break;
			} else if(error) {
				PrintAPIError (error);
				break;
			}
		}


  }   /* end of while loop */

	
}

/************************************************************************

    FUNCTION:   extract single attachment

 ************************************************************************/

void extractSingleAttachment(NOTEHANDLE  note_handle,NOTEID noteID,BLOCKID item_blockid,BLOCKID value_blockid,char* attachments){
	STATUS       error;
	char         *pObject;
	FILEOBJECT   fileObject;
	char         *szFileName;
	char         fileName[260];

//		TYPE_OBJECT

	/* assign pointer to item, and skip over TYPE_OBJECT word */
	pObject = OSLockBlock(char, value_blockid);
	pObject += ODSLength(_WORD);

	/* Read in the OBJECT_DESCRIPTOR ODS record and ensure that there are 
		data objects */
	ODSReadMemory( &pObject, _FILEOBJECT, &fileObject, 1 );
	szFileName = (char *) malloc(fileObject.FileNameLength+1);

	if(szFileName==NULL){
		OSUnlockBlock(value_blockid);
		return;
	}

	memcpy(szFileName,pObject,fileObject.FileNameLength);
	szFileName[fileObject.FileNameLength]='\0';
	
	OSUnlockBlock(value_blockid);


	itoa( noteID, fileName, 10 ); 
	strcat_s(fileName,260,"_");
	strcat_s(fileName,260,szFileName);

	strcat_s(attachments,260,szFileName);
	strcat_s(attachments,260,",");

	if(error=NSFNoteCipherExtractFile(note_handle,
							 item_blockid,
							 0,
							 NULLCIPHERHANDLE,
							 fileName,
							 0,
							 NULL)){
		PrintAPIError (error);
	}

	free(szFileName);
	   
	
}


/*************************************************************************

    FUNCTION:   PrintAPIError

    PURPOSE:    This function prints the Lotus C API for Domino and Notes 
		error message associated with an error code.

**************************************************************************/

void PrintAPIError (STATUS api_error)

{
    STATUS  string_id = ERR(api_error);
    char    error_text[200];
    WORD    text_len;

    /* Get the message for this Lotus C API for Domino and Notes error code
       Body the resource string table. */

    text_len = OSLoadString (NULLHANDLE,
                             string_id,
                             error_text,
                             sizeof(error_text));

    /* Print it. */
    fprintf (stderr, "\n%s\n", error_text);

}

